package main

import (
	"database/sql"
	"encoding/json"
	"errors"
	"fmt"
	"log"

	_ "github.com/mattn/go-sqlite3"
)

/*
main.db
create table if not exists flowIndex (id INTEGER PRIMARY KEY AUTOINCREMENT,title text);
create table if not exists flowID (id INTEGER PRIMARY KEY AUTOINCREMENT,name text,idx int,status int,depend text);
#depend: json
*/
var conn1 *sql.DB

func init() {
	var err error
	conn1, err = sql.Open("sqlite3", "./main.db")
	if err != nil {
		panic(err)
	}
}
func CreateFlow(title string) (insertID int, err1 error) {
	_, err := conn1.Exec("create table if not exists flowIndex (id INTEGER PRIMARY KEY AUTOINCREMENT,title text);")
	if err != nil {
		log.Println("create flowIndex")
		return 0, err
	}
	tx, err := conn1.Begin()
	_, err = tx.Exec("insert into flowIndex(title) values(?);", title)
	if err != nil {
		log.Println("insert title")
		return 0, errors.New("insert title")
	}
	res := tx.QueryRow("select max(id) from flowIndex;")
	var id int
	err = res.Scan(&id)
	if err != nil {
		tx.Rollback()
		return 0, err
	}
	sql1 := fmt.Sprintf("create table if not exists flow%d (id INTEGER PRIMARY KEY AUTOINCREMENT,name text,idx int,status int,depend text);", id)
	_, err = tx.Exec(sql1)
	if err != nil {
		log.Println("create flowN")
		tx.Rollback()
		return 0, errors.New("create flowN:" + err.Error())
	}
	err = tx.Commit()
	return id, err
}

type FlowInfo struct {
	Id    int
	Title string
}

func GetFlows() []FlowInfo {
	sql1 := "select id,title from flowIndex order by id asc;"
	res, err := conn1.Query(sql1)
	if err != nil {
		return nil
	}
	var ret = make([]FlowInfo, 0)
	for res.Next() {
		var row1 FlowInfo
		res.Scan(&row1.Id, &row1.Title)
		ret = append(ret, row1)
	}
	res.Close()
	return ret
}

func GetTreeByID(id int) (map1 MapOpNode, title string, err error) {
	row := conn1.QueryRow("select title from flowIndex where id=?;", id)
	row.Scan(&title)

	sql1 := fmt.Sprintf("select id,name,idx,status,depend from flow%d;", id)
	res, err := conn1.Query(sql1)
	if err != nil {
		return nil, "", err
	}
	defer res.Close()
	map1 = make(MapOpNode)
	for res.Next() {
		var v OpNode
		var json1 []byte
		res.Scan(&v.ID, &v.Name, &v.Index, &v.Status, &json1)
		err = json.Unmarshal(json1, &v.Before)
		if err != nil {
			return nil, "", err
		}
		map1[v.ID] = &v
	}
	return map1, title, err
}

//InsertNode
func InsertNode(tblName, nodeName string, status int, depend []int) error {
	var idx int
	tx, err := conn1.Begin()
	if err != nil {
		log.Println("tx Begin")
		return err
	}
	row := tx.QueryRow(fmt.Sprintf("select count(*) from %s;", tblName))
	err = row.Scan(&idx)
	if err != nil {
		log.Println("select count")
		return err
	}
	json1, err := json.Marshal(depend)
	if err != nil {
		log.Println("json.Marshal")
		return err
	}
	sql1 := fmt.Sprintf("insert into %s (name,idx,status,depend) values(?,?,?,?);", tblName)
	tx.Exec(sql1, nodeName, idx, status, json1)
	return tx.Commit()
}

func InsertNode2(tblName, nodeName string, id, status int, depend []int) error {
	var idx int
	tx, err := conn1.Begin()
	if err != nil {
		log.Println("tx Begin")
		return err
	}
	row := tx.QueryRow(fmt.Sprintf("select count(*) from %s;", tblName))
	err = row.Scan(&idx)
	if err != nil {
		log.Println("select count")
		return err
	}
	json1, err := json.Marshal(depend)
	if err != nil {
		log.Println("json.Marshal")
		return err
	}
	sql1 := fmt.Sprintf("insert into %s (id,name,idx,status,depend) values(?,?,?,?,?);", tblName)
	tx.Exec(sql1, id, nodeName, idx, status, json1)
	return tx.Commit()
}

//UpdateNode
func UpdateNode(tblName string, id int, nodeName string, status int, depend []int) error {
	json1, err := json.Marshal(depend)
	if err != nil {
		return err
	}
	sql1 := fmt.Sprintf("update %s set name=?,status=?,depend=? where id=?;", tblName)
	_, err = conn1.Exec(sql1, nodeName, status, json1, id)
	return err
}

//SwapIndex
func SwapIndex(tblName string, id1, id2 int) error {
	tx, err := conn1.Begin()
	if err != nil {
		return err
	}
	var idx1, idx2 int
	sql1 := fmt.Sprintf("select idx from %s where id=?;", tblName)
	row := tx.QueryRow(sql1, id1)
	err = row.Scan(&idx1)
	if err != nil {
		return err
	}
	row = tx.QueryRow(sql1, id2)
	err = row.Scan(&idx2)
	if err != nil {
		return err
	}
	//update
	sql1 = fmt.Sprintf("update %s set idx=? where id=?", tblName)
	_, err = tx.Exec(sql1, idx1, id2)
	if err != nil {
		return err
	}
	_, err = tx.Exec(sql1, idx2, id1)
	if err != nil {
		return tx.Rollback()
	} else {
		return tx.Commit()
	}
}

type NodeInfo struct {
	Id     int
	Depend []int
	Status int // 0 can not start, 1 can do, 2 doing, 3 done
	Index  int //sort
	Name   string
	FlowID int
}

func GetNodeInfo(flowID, nodeID int) *NodeInfo {
	var tblName = fmt.Sprintf("flow%d", flowID)
	sql1 := fmt.Sprintf("select name,idx,status,depend from %s where id=?", tblName)
	var res NodeInfo
	res.Id = nodeID
	res.FlowID = flowID
	var json1 []byte
	row := conn1.QueryRow(sql1, nodeID)
	err := row.Scan(&res.Name, &res.Index, &res.Status, &json1)
	if err != nil {
		log.Printf("GetNode:%v", err)
		return nil
	}
	err = json.Unmarshal(json1, &res.Depend)
	if err != nil {
		log.Printf("GetNode:%v", err)
		return nil
	}
	return &res
}

func DelNode(flowID, nodeID int) error {
	sql1 := fmt.Sprintf("delete from flow%d where id=?", flowID)
	if IsAlone(flowID, nodeID) {
		_, err := conn1.Exec(sql1, nodeID)
		return err
	} else {
		return errors.New("Not alone.")
	}
}
